package oop.ex3.filemanager;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketTimeoutException;
import java.util.LinkedList;
import java.util.Scanner;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import oop.ex3.protocol.*;
import oop.ex3.sharedclasses.IPaddress;
import oop.ex3.usercommands.*;

public class MyFileManager {

	private static final int PORT_ARG_INDEX=2,
							DIR_ARG_INDEX=1,
							SERVERFILE_ARG_INDEX=0,
							TIMEOUT_5_SECONDS=5000;
	private static final boolean FAILURE = false;
	private static final boolean SUCCESS = true;
	private static final UserMessage NO_SUCH_MESSAGE = null;
	private static final int MESSAGE_NAME = 0;
	private static final int FILENAME_INDEX = 1, NEW_NAME_INDEX=2;
	
	
	
	public static void main(String[] args){
	// Initiates the nameServer
	FileManager fileManager=new FileManager(args[SERVERFILE_ARG_INDEX],
											args[DIR_ARG_INDEX],
										Integer.parseInt(args[PORT_ARG_INDEX]));
		Socket clientSocket;
		
		announceCreation(fileManager);
		UploadRequestThread requestThread = new UploadRequestThread(fileManager);
		requestThread.start();
		
		Scanner inputScanner = new Scanner(System.in);
		String input = inputScanner.nextLine();
		while (!input.equals(Quit.COMMAND)){
			UserMessage userMessage = generateMessage(fileManager,input, inputScanner);
			System.out.println(userMessage.getClass());
			userMessage.run();
			input = inputScanner.nextLine();
		}
		
		if (input.equals(Quit.COMMAND)){
			Quit quit = new Quit(fileManager);
			quit.run();
		}
		
		return;
	}

	private static void announceCreation(FileManager fileManager) {
		LinkedList<IPaddress> nameServers = fileManager.getNameServerList();
		for (IPaddress ns : nameServers){
			announceServer(fileManager, ns);
		}
	}
	
	private static boolean announceServer(FileManager fileManager, IPaddress serverIP){
		//initiates connection:
		SocketAddress targetAddress = 
				new InetSocketAddress(serverIP.getIP(),serverIP.getPort());
		Socket session = new Socket();
		DataInputStream input=null;
		DataOutputStream output=null;
		
		try{
			
		session.connect(targetAddress, TIMEOUT_5_SECONDS);
		input = new DataInputStream (session.getInputStream());
		output = new DataOutputStream(session.getOutputStream());
		
		//Begins a the session according to protocol.
		Begin newSession = new Begin();
		EndSession endSession = new EndSession();
		
		if (newSession.runAsClient(fileManager, input, output)==FAILURE
			|| endSession.runAsClient(input, output)==FAILURE){
				if (endSession.runAsClient(input, output)==FAILURE){
					//TODO make sure to debug later! no bugs found yet.
					System.out.println("Invalid session termination:No final response from NameServer");
					return FAILURE;
				}
				
			/* if one of the actions fails, and the endSession is successful,
			 * everything will continue normally - 
			 * SUCCESS sent even though the actual process failed.
			 */
			return SUCCESS;
		}
		
		}catch (IOException e){
			// socket opening failed
		}finally{
			try {
				input.close();
				output.close();
				session.close();
			} catch (Exception e) {
				//Ignored exception - stream & socket closing exceptions
			}
		}
		
		return SUCCESS;
	}
	
	
	//TODO remove quit from options and edit javadoc
	/**
	 * Generates a MessageHandler according to <message> input.
	 * Will return an instance of the correct MessageHandler
	 * that fits the input <message> String.
	 * The generator will not generate Begin, End Session or Go away
	 * since they are all treated differently than a standard message.
	 * @param fileManager the fileManager calling the message.
	 * @param message the input Message String.
	 * @param inputScanner a scanner to get user input.
	 * @return an instance of MessageHandler matching input <message>,
	 * 			or NO_SUCH_MESSAGE (=null object) if no matching Handler
	 * 			exists (<=> Message not in protocol).
	 */
	private static UserMessage generateMessage(FileManager fileManager,
			String message, Scanner inputScanner){
		//TODO check if BEGIN and ENDSESSION are needed.
		String[] messageParts = message.split(" ");
		if (messageParts[MESSAGE_NAME].equals(Add.COMMAND)){
			return new Add(fileManager, messageParts[FILENAME_INDEX]);
		}
		else if (messageParts[MESSAGE_NAME].equals(Dir.COMMAND)){
			return new Dir(fileManager);
		}
		else if (messageParts[MESSAGE_NAME].equals(DirServers.COMMAND)){
			return new DirServers(fileManager);
		}
		else if (messageParts[MESSAGE_NAME].equals(FireServers.COMMAND)){
			return new FireServers(fileManager);
		}
		else if (messageParts[MESSAGE_NAME].equals(DirAllFiles.COMMAND)){
			return new DirAllFiles(fileManager);
		}
		else if (messageParts[MESSAGE_NAME].equals(Remove.COMMAND)){
			return new Remove(fileManager,messageParts[FILENAME_INDEX]);
		}
		else if (messageParts[MESSAGE_NAME].equals(Rename.COMMAND)){
			return new Rename(fileManager,messageParts[FILENAME_INDEX],
									messageParts[NEW_NAME_INDEX]);
		}
		else{
			return NO_SUCH_MESSAGE;
		}
	}
}